#include "Parser.h"
#include "Text/Convert.h"
#include <locale>

bool Parser::EndOfText()
{
	if(*now == _RBT('\0'))
		return true;
	return false;
}

bool Parser::MoveNext()
{
	if(EndOfText())
		return false;
	now += 1;
	next+= 1;
	return true;
}

bool Parser::IsOperator( ctchar* v /*= 0*/ )
{
	if(v == 0)
		v = now;
	if( *v == _RBT('=') )
		return true;
	return false;
}

bool Parser::IsValue( ctchar& v , ctchar* p /*= 0*/ )
{
	if(p==0)
		p = now;
	return v == *p;
}

bool Parser::IsRange( ctchar& lhs ,ctchar& rhs , ctchar* v )
{
	if(v==0)
		v=now;
	return (*v >= lhs && *v <= rhs );
}

bool Parser::IsKeyword( ctchar* v )
{
	if( 
		IsRange(_RBT('a') , _RBT('z') , v ) ||
		IsRange(_RBT('A') , _RBT('Z') , v ) ||
		IsRange(_RBT('0') , _RBT('9') , v ) ||
		IsValue(_RBT('_') , v ) 
		)
	{
		return true;
	}
	return false;
}

bool Parser::IsNumber( ctchar* v /*= 0 */ )
{
	return IsRange(_RBT('0') ,_RBT('9') , v ) ;
}

bool Parser::IsAllWord( ctchar* v/*=0*/ )
{
	if( 
		IsValue(_RBT('['),v) || 
		IsValue(_RBT(']'),v) ||
		IsValue(_RBT('\"'),v)||
		IsValue(_RBT('-') ,v)||
		IsValue(_RBT('{') ,v)||
		IsValue(_RBT('}'),v )||
		IsKeyword(v) )
	{
		return true;
	}

	return false;
}

bool Parser::IsSpace( ctchar* v/*=0*/ )
{
	if(v==0)
		v=now;
	return isspace( *now , std::locale());
}

bool Parser::IsEndLine( ctchar* v /*= 0 */ )
{
	return IsValue(_RBT(',') , v ) || 
		IsValue(_RBT(']') , v ) ||
		IsValue(_RBT('}') , v );
}

int32 Parser::ReadOper( string& op )
{
	token = now;
	do 
	{
		if( IsAllWord() || IsSpace() )
		{
			op.append(token,now);
			if(op.empty())
				return E_EMPTY_KEY;
			else
				return R_SUCCEED;
		}
	} while (MoveNext());
	return E_PARSE_ERROR;
}

void Parser::SkipSpace()
{
	do 
	{
		if(IsSpace())
		{
			continue;
		}
		else
		{
			return;
		}
	} while (MoveNext());
}

int32 Parser::SkipEndLine()
{
	token = now;

	if(IsValue(_RBT('\0')))
		return R_SUCCEED;

	if(!IsSpace() && !IsValue(_RBT('\0'),next))
		return E_PARSE_ERROR;

	do
	{
		if( !IsSpace() )
		{
			return R_SUCCEED;
		}
	}while( MoveNext() );
	return R_SUCCEED;
}

int32 Parser::ReadKey( string& key )
{
	key.clear();
	token = now;
	do
	{
		if( IsOperator() || IsSpace() )
		{
			key.append( token , now );
			if(key.empty())
			{
				return E_EMPTY_KEY;
			}
			else
			{
				return R_SUCCEED;
			}
		}
	} while (MoveNext());
	return E_PARSE_ERROR;
}

int32 Parser::ReadValue( Object& object )
{
	int32 type        = TYPE_VALUE;
	int32 dotCount    = 0;
	string valueString;

	token = now;

	if( IsValue(_RBT('-') ) )
	{
		type = TYPE_SIGNED;
	}

	int32 code = E_PARSE_ERROR;;

	while(MoveNext())
	{

		if( IsEndLine() || IsSpace() || IsValue(_RBT('\0')))
		{
			valueString.append(token,now);
			if( valueString == _RBT("-") )
				code = E_PARSE_ERROR;
			else
			{
				code = R_SUCCEED;
				break;
			}
		}

		if(IsValue(_RBT('.')) && IsNumber(next) )
		{
			type = TYPE_FOLAT;
			dotCount++;
			if(dotCount>1)
				return E_PARSE_ERROR;
			continue;
		}

		if(!IsNumber())
		{
			code = E_PARSE_ERROR;
			break;
		}
	}

	if(code != R_SUCCEED)
		return code;

	if( type== TYPE_FOLAT )
	{
		float64 value = 0;
		code = Convert::ToFloat64( valueString , value );
		if( code == R_SUCCEED )
			code = object.Initalize( value );
	}
	else if( type == TYPE_SIGNED )
	{
		int64 value = 0;
		code = Convert::ToInt64( valueString , value );
		if(code == R_SUCCEED)
		{
			if( IsValueType<int32>(value) )
			{
				int32 cvt = static_cast<int32>(value);
				code = object.Initalize(cvt);
			}
			else
			{
				code = object.Initalize(value);
			}
		}
	}
	else if(type == TYPE_VALUE)
	{
		uint64 value = 0;
		code = Convert::ToUInt64( valueString , value );
		if(code == R_SUCCEED)
		{
			if(value < INT_MAX)
			{
				int32 cvt = static_cast<int32>(value);
				code = object.Initalize(cvt);
			}
			else if( value < UINT_MAX )
			{
				uint32 cvt = static_cast<uint32>(value);
				code = object.Initalize(cvt);
			}
			else if( value < LLONG_MAX )
			{
				int64 cvt = static_cast<int64>(value);
				code = object.Initalize(cvt);
			}
			else
			{
				code = object.Initalize( value );
			}
		}
	}

	return code;
}

int32 Parser::ReadKeyValue( Object& object )
{
	token = now;
	KeyValue read;
	int32  code = E_PARSE_ERROR; 

	while(MoveNext())
	{
		string key;
		string oper;
		Object value;

		SkipSpace();
		code = ReadKey( key );
		if( code != R_SUCCEED )
			goto Exit0;

		SkipSpace();

		int32 code = ReadOper(oper);

		if(code != R_SUCCEED)
			goto Exit0;

		SkipSpace();

		code = AutoReadValue( value );

		if(code == R_SUCCEED)
		{
			read.Set(key,value);
		}
		else
		{
			goto Exit0;
		}

		SkipSpace();

		if(IsValue(_RBT('}')))
		{
			MoveNext();
			code = R_SUCCEED;
			goto Exit0;
		}

		if(IsValue(_RBT(',')))
		{
			code = E_PARSE_ERROR;
			continue;
		}
		else
		{
			code = E_PARSE_ERROR;
			break;
		}
	}
Exit0:
	if(code != R_SUCCEED)
		read.Uninitalize();
	else
		object.Initalize(read);

	MoveNext();
	return code;
}

int32 Parser::AutoReadValue( Object& object )
{
	int32 code = E_PARSE_ERROR;

	if( IsNumber() || IsValue(_RBT('-')) )
	{
		code = ReadValue( object );
	}
	else if( IsValue(_RBT('\"')) )
	{
		code = ReadString( object );
	}

	return code;
}

int32 Parser::ReadArray( Object& object )
{
	token = now;
	Array read;
	int32 code = R_FAILED;
	while(MoveNext())
	{
		SkipSpace();

		Object readObject;

		code = AutoReadValue( readObject );

		if( code == R_SUCCEED )
		{
			read.Add( readObject );
		}
		else
		{
			goto Exit0;
		}

		SkipSpace();
		if( IsValue(_RBT(']') ) )
		{
			MoveNext();
			code = R_SUCCEED;
			goto Exit0;
		}

		if( IsValue(_RBT(',')) )
		{
			code = E_PARSE_ERROR;
			continue;
		}
		else
		{
			code = E_PARSE_ERROR;
			break;
		}
	}

Exit0:
	if(code != R_SUCCEED)
		read.Uninitalize();
	else
		object.Initalize(read);

	MoveNext();
	return code;
}

int32 Parser::ReadString( Object& object )
{
	token = next;
	while(MoveNext())
	{
		if( IsValue('\"') && 
			( ( IsSpace(next) || IsValue(_RBT('\0') , next ) )  ||
			IsValue('\"'))
			)
		{
			cstring value( token , now );
			int32 code = object.Initalize( value );
			if( code != R_SUCCEED )
				return code;
			MoveNext();
			return R_SUCCEED;
		}
	}
	return E_PARSE_ERROR;
}

int32 Parser::End()
{
	if(EndOfText())
		return R_SUCCEED;
	return R_FAILED;
}

int32 Parser::ReadObject( string& keyName , string& opName , Object& valueObject )
{
	int32 code = E_PARSE_ERROR;
	keyName.clear();
	opName.clear();

	SkipSpace();

	if(IsValue(_RBT('\0')))
		return R_SUCCEED;

	//ReadKey
	code = ReadKey( keyName );
	if(code!=R_SUCCEED)
		return code;

	SkipSpace();

	code = ReadOper( opName );
	if(code!=R_SUCCEED)
		return code;

	SkipSpace();

	if( IsNumber() || IsValue(_RBT('-')) )
	{
		code = ReadValue( valueObject );
	}
	else if( IsValue( _RBT('\"') ) )
	{
		code = ReadString( valueObject );
	}
	else if( IsValue( _RBT('{') ) )
	{
		code = ReadKeyValue(valueObject);
	}
	else if( IsValue( _RBT('[' ) ) )
	{
		code = ReadArray( valueObject );
	}
	else
	{
		return E_PARSE_ERROR;
	}

	if(code!=R_SUCCEED)
		return code;

	code = SkipEndLine();

	return code;
}

int32 Parser::Initialize( cstring& text )
{
	now   = text.c_str();
	next  = now + 1;
	token = now;
	end   = text.c_str() + text.size() + 1;
	return R_SUCCEED;
}